#include <iostream>
#include <fstream>

#include "linked_list.h"

using namespace std;


//------------ Functions

int add(int, int);
int mult(int, int);

void zeroIt(int &);
void print(int);

//------------ Functors

class MaxFunctor {
public:
	int operator ()(int x, int y) {return x > y ? x : y;}
};

class MinFunctor {
public:
	int operator ()(int x, int y) {return x < y ? x : y;}
};

class PrintFunctor {
public:
	PrintFunctor(ostream &os = cout) : os(os), count(0) {}
	void operator ()(int x) {os << x << " "; count++;}	
	ostream &os;
	int count;
};

//------------ Algorithms

template <typename ITERATOR, typename BINARY_FUNCTION>
int accum(ITERATOR first, ITERATOR last, BINARY_FUNCTION &f);

template <typename ITERATOR, typename UNARY_FUNCTION>
void for_each(ITERATOR first, ITERATOR last, UNARY_FUNCTION &f);


int main()
{
	LinkedList list;
   list.insert(1);
   list.insert(2);
   list.insert(3);
   list.insert(4);
   list.insert(5);
   
	cout << "List: " << endl;
   for_each(list.begin(), list.end(), print);
	cout << endl;

	cout << "----- Summing" << endl;
	cout << accum(list.begin(), list.end(), add) << endl;
	cout << endl;
	
	cout << "----- Producting" << endl;
	cout << accum(list.begin(), list.end(), mult) << endl;
	cout << endl;

	MaxFunctor maxf;
	cout << "----- Max'ing" << endl;
	cout << accum(list.begin(), list.end(), maxf) << endl;
	cout << endl;

	MinFunctor minf;
	cout << "----- Min'ing" << endl;
	cout << accum(list.begin(), list.end(), minf) << endl;
	cout << endl;
	
	cout << "----- Printing" << endl;
	for_each(list.begin(), list.end(), print);
	cout << endl;
	
	cout << "----- Better Printing" << endl;
	ofstream ofs("listPrint.txt");
	PrintFunctor pf(ofs);
	for_each(list.begin(), list.end(), pf);
	ofs << " -- " << pf.count << " elements printed" << endl;

	return 0;
}


//------------------ Algorithms

template <typename ITERATOR, typename BINARY_FUNCTION>
int accum(ITERATOR first, ITERATOR last, BINARY_FUNCTION &f) {
	int result = *first;
	++first;
	for (ITERATOR iter = first; iter != last; ++iter)
		result = f(result, *iter);	
	return result;
}

template <typename ITERATOR, typename UNARY_FUNCTION>
void for_each(ITERATOR first, ITERATOR last, UNARY_FUNCTION &f) {
	for (ITERATOR iter = first; iter != last; ++iter)
		f(*iter);	
}


//---------------- Functions
int add(int x, int y) {return x+y;}
int mult(int x, int y) {return x * y;}

void print(int x) {cout << x << " ";}


